/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { TypeNode } from 'ts-morph';
import { ITypeHandler, TypeContext, ConversionDirection } from './ITypeHandler';
import { PropertyKind, SerializerMetadata, TypeStructure } from '../Types';

export abstract class BaseTypeHandler implements ITypeHandler {
  abstract readonly name: string;
  abstract readonly kind: PropertyKind;
  abstract readonly priority: number;

  // 子类必须实现的所有核心方法
  abstract matches(typeNode: TypeNode, context: TypeContext): boolean;
  abstract parse(typeNode: TypeNode, context: TypeContext): TypeStructure;
  abstract getSerializerMetadata(structure: TypeStructure, withParam?: string): SerializerMetadata;
  abstract generateInstantiation(structure: TypeStructure): string;
  abstract generateTypeDeclaration(structure: TypeStructure): string;
  abstract generateTypeKey(structure: TypeStructure): string;
  abstract generateSendableTypeDeclaration(structure: TypeStructure): string;
  abstract generatePropertyConversion(structure: TypeStructure, sourceValue: string, direction: ConversionDirection): string;

  /** 获取序列化器名称（约定：TypeName + Serializer）*/
  protected getSerializerName(): string {
    return `${this.getTypeName()}Serializer`;
  }

  /** 获取类型名称 */
  protected getTypeName(): string {
    return this.capitalize(this.kind);
  }

  /** 首字母大写 */
  protected capitalize(str: string): string {
    return str.charAt(0).toUpperCase() + str.slice(1);
  }

  // ==================== With参数处理 ====================

  /**
   * 应用with参数覆盖默认的序列化器实例化代码
   * @param withParam 自定义序列化器表达式
   * @param defaultInstantiation 默认实例化代码
   * @param structure 类型结构
   */
  protected applyWithParam(withParam: string | undefined, defaultInstantiation: string, structure: TypeStructure): string {
    if (!withParam) {
      return defaultInstantiation;
    }

    // 检查是否包含泛型类型
    if (this.containsGenericType(structure)) {
      return `new WithEntrySerializer(${withParam}, [${this.generateTypeKeySerializers(structure)}])`;
    } else {
      return `new WithEntryContextualSerializer(${withParam}, [${this.generateTypeKeys(structure)}])`;
    }
  }

  /**
   * 检查类型结构中是否包含泛型类型参数
   */
  protected containsGenericType(structure: TypeStructure): boolean {
    // 检查当前节点是否为泛型
    if (structure.kind === PropertyKind.GENERIC) {
      return true;
    }

    // 递归检查泛型参数（如 Array<T>, Map<K,V>）
    if (structure.args && structure.args.length > 0) {
      return structure.args.some(arg => this.containsGenericType(arg));
    }

    // 递归检查联合类型的成员（如 T | string | number）
    if (structure.unionDetails && structure.unionDetails.length > 0) {
      return structure.unionDetails.some(member => this.containsGenericType(member));
    }

    return false;
  }

  /**
   * 生成类型键序列化器数组（用于泛型类型的with参数）
   * @example Array<T> -> [Serializer<T>]
   */
  protected generateTypeKeySerializers(structure: TypeStructure): string {
    if (structure.args && structure.args.length > 0) {
      // 需要导入TypeHandlerRegistry来生成实例化代码
      const { TypeHandlerRegistry } = require('./TypeHandlerRegistry');
      return structure.args.map((arg) => {
        return TypeHandlerRegistry.getInstance().generateInstantiation(arg);
      }).join(',\n');
    }
    return '';
  }

  /**
   * 生成类型键数组（用于非泛型类型的with参数）
   * @example Array<string> -> ['string']
   */
  protected generateTypeKeys(structure: TypeStructure): string {
    if (structure.args && structure.args.length > 0) {
      const { TypeHandlerRegistry } = require('./TypeHandlerRegistry');
      return structure.args.map(arg => {
        return TypeHandlerRegistry.getInstance().generateTypeKey(arg);
      }).join(', ');
    }
    return '';
  }
}